package org.yjc.custom;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JqgridParam {
	private Integer page; // 页号
	private Integer rows; // 每页行数
	private Boolean search = false; // 是否筛选
	private String sidx; // 排序字段
	private String sord; // 排序方式
	private String searchField;
	private String searchOper;
	private String searchString;
	private String filters;

	public Integer getPage() {
		return page;
	}

	public void setPage(Integer page) {
		this.page = page;
	}

	public Integer getRows() {
		return rows;
	}

	public void setRows(Integer rows) {
		this.rows = rows;
	}

	public Boolean getSearch() {
		return search;
	}

	public void setSearch(Boolean search) {
		this.search = search;
	}

	public String getSidx() {
		return sidx;
	}

	public void setSidx(String sidx) {
		this.sidx = sidx;
	}

	public String getSord() {
		return sord;
	}

	public void setSord(String sord) {
		this.sord = sord;
	}

	public Pageable buildPageable() {
		page--;
		Sort sort = Sort.by(Direction.fromString(sord), sidx);
		return PageRequest.of(page, rows, sort);
	}

	public String getSearchField() {
		return searchField;
	}

	public void setSearchField(String searchField) {
		this.searchField = searchField;
	}

	public String getSearchOper() {
		return searchOper;
	}

	public void setSearchOper(String searchOper) {
		this.searchOper = searchOper;
	}

	public String getSearchString() {
		return searchString;
	}

	public void setSearchString(String searchString) {
		this.searchString = searchString;
	}

	public String getFilters() {
		return filters;
	}

	public void setFilters(String filters) {
		this.filters = filters;
	}

	public Specification buildSpec() {
		Specification specification = new Specification() {

			@Override
			public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
			
				Predicate predicate = null;
				if (StringUtils.hasText(filters)) {
					ObjectMapper mapper = new ObjectMapper();
					try {
						Filters muliFilters = mapper.readValue(filters, Filters.class);
						HashSet<Predicate> rules = new HashSet<>();
						for (Rule rule : muliFilters.getRules()) {
							Expression field = root.get(rule.getField());
							if ("eq".equals(rule.getOp())) {
								rules.add(cb.equal(field, rule.getData()));
							}
							if ("ne".equals(rule.getOp())) {
								rules.add(cb.notEqual(field, rule.getData()));
							}
							if ("lt".equals(rule.getOp())) {
								rules.add(cb.lessThan(field, rule.getData()));
							}
							if ("le".equals(rule.getOp())) {
								rules.add(cb.lessThanOrEqualTo(field, rule.getData()));
							}
							if ("gt".equals(rule.getOp())) {
								rules.add(cb.greaterThan(field, rule.getData()));
							}
							if ("ge".equals(rule.getOp())) {
								rules.add(cb.greaterThanOrEqualTo(field, rule.getData()));
							}
							if ("bw".equals(rule.getOp())) {
								rules.add(cb.like(field, rule.getData() + "%"));
							}
							if ("bn".equals(rule.getOp())) {
								rules.add(cb.notLike(field, rule.getData() + "%"));
							}
							if ("in".equals(rule.getOp())) {
								List<String> strings = new ArrayList<String>();
								split(rule.getData(), strings);
								rules.add(field.in(strings).not());
							}
							if ("ni".equals(rule.getOp())) {
								List<String> strings = new ArrayList<String>();
								split(rule.getData(), strings);
								rules.add(field.in(strings));
							}
							if ("ew".equals(rule.getOp())) {
								rules.add(cb.like(field, "%" + rule.getData()));
							}
							if ("en".equals(rule.getOp())) {
								rules.add(cb.notLike(field, "%" + rule.getData()));
							}
							if ("cn".equals(rule.getOp())) {
								rules.add(cb.like(field, "%" + rule.getData() + "%"));
							}
							if ("nc".equals(rule.getOp())) {
								rules.add(cb.notLike(field, "%" + rule.getData() + "%"));
							}
						}
						if ("AND".equals(muliFilters.getGroupOp())) {
							predicate = cb.and(rules.toArray(new Predicate[rules.size()]));
						} else {
							predicate = cb.or(rules.toArray(new Predicate[rules.size()]));
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				} else {
					Expression exp = root.get(searchField);
					if ("eq".equals(searchOper)) {
						predicate = cb.equal(exp, searchString);
					}
					if ("ne".equals(searchOper)) {
						predicate = cb.notEqual(exp, searchString);
					}
					if ("lt".equals(searchOper)) {
						predicate = cb.lessThan(exp, searchString);
					}
					if ("le".equals(searchOper)) {
						predicate = cb.lessThanOrEqualTo(exp, searchString);
					}
					if ("gt".equals(searchOper)) {
						predicate = cb.greaterThan(exp, searchString);
					}
					if ("ge".equals(searchOper)) {
						predicate = cb.greaterThanOrEqualTo(exp, searchString);
					}
					if ("bw".equals(searchOper)) {
						predicate = cb.like(exp, searchString + "%");
					}
					if ("bn".equals(searchOper)) {
						predicate = cb.notLike(exp, searchString + "%");
					}
					if ("in".equals(searchOper)) {
						List<String> strings = new ArrayList<String>();
						split(searchString, strings);
						predicate = exp.in(strings).not();
					}
					if ("ni".equals(searchOper)) {
						List<String> strings = new ArrayList<String>();
						split(searchString, strings);
						predicate = exp.in(strings);
					}
					if ("ew".equals(searchOper)) {
							predicate = cb.like(exp, "%" + searchString);

						if ("en".equals(searchOper)) {
							predicate = cb.notLike(exp, "%" + searchString);
						}
						if ("cn".equals(searchOper)) {
							predicate = cb.like(exp, "%" + searchString + "%");
						}
						if ("nc".equals(searchOper)) {
							predicate = cb.notLike(exp, "%" + searchString + "%");
						}
					}
				}
				return predicate;
			}
		};
		return specification;
	}

	public void split(String str, List<String> list) {
		if (str.contains(",") || str.contains("，")) {
			if (str.contains(",")) {
				String[] s = StringUtils.split(str, ",");
				list.add(s[0]);
				split(s[1], list);
			}
			if (str.contains("，")) {
				String[] s = StringUtils.split(str, "，");
				list.add(s[0]);
				split(s[1], list);
			} else {
				list.add(str);
			}
		 }
	}

}
